using System.Threading;
using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour {

    [Header("事件监听")]
    public SceneLoadEventSO sceneLoadEventSO;   // 场景加载事件监听
    public VoidEventSO afterSceneLoaded;        // 场景加载完毕后 
    public VoidEventSO loadDataEvent;           // 加载数据的事件监听
    public VoidEventSO backToMenuEvent;         // 返回到主菜单的事件监听

    [Header("输入系统")]
    public PlayerInputController inputControl;  // 输入控制系统
    public Vector2 inputDirection;              // wasd输入方向

    private Rigidbody2D rb;                     // 2D刚体组件
    private PhysicsCheck physicsCheck;          // PhysicsCheck脚本
    private CapsuleCollider2D colli;            // 2D胶囊碰撞体组件
    private PlayerAnimaition playerAnimation;   // PlayerAnimation脚本组件

    [Header("基本参数")]
    public float speed;             // 人物默认移动速度（跑步速度）
    public float jumpForce;         // 跳跃的力
    public float wallJumpForce;     // 蹬墙跳的力
    public float hurtForce;         // 受伤的后退的力
    public float slideDistance;     // 滑铲的距离
    public float slideSpeed;        // 滑铲的距离
    public float slidePowerCost;    // 滑铲消耗的能量

    private float runSpeed;         // 跑步速度
    private float walkSpeed;        // 行走速度
    private Vector2 originalSize;   // 碰撞体的起始大小 
    private Vector2 originalOffset; // 碰撞体的起始偏移量
    private Character character;
    
    [Header("物理材质")]
    public PhysicsMaterial2D normal;
    public PhysicsMaterial2D wall;

    [Header("状态")]
    public bool isCrouch;       // 是否蹲下
    public bool isHurt;         // 当前是否是受伤状态
    public bool isDead;         // 当前是否dead
    public bool isAttack;       // 当前是否正在攻击
    public bool isWallJump;     // 当前是否正在蹬墙跳
    public bool isSlide;        // 当前是否正在滑铲

    private void Awake() {
        rb = GetComponent<Rigidbody2D>();
        physicsCheck = GetComponent<PhysicsCheck>();
        inputControl = new PlayerInputController();
        colli = GetComponent<CapsuleCollider2D>();
        playerAnimation = GetComponent<PlayerAnimaition>();
        character = GetComponent<Character>();
        originalOffset = colli.offset;
        originalSize = colli.size;

        // 按键控制开启
        inputControl.Enable();

        // 跳跃按钮事件绑定
        inputControl.GamePlay.Jump.started += Jump;

        // 攻击按钮事件绑定
        inputControl.GamePlay.Attack.started += Attack;

        // 滑铲按钮事件绑定
        inputControl.GamePlay.Slide.started += Slide;
        
        #region 强制走路
        runSpeed = speed;
        walkSpeed = speed / 2.5f;
        inputControl.GamePlay.Walk.performed += CallbackContext => {
            if (physicsCheck.isGround) {
                speed = walkSpeed;
            }
        };

        inputControl.GamePlay.Walk.canceled += CallbackContext => {
            speed = runSpeed;
        };
        #endregion 强制走路
    }

    private void OnEnable() {
        sceneLoadEventSO.LoadRequestEvent += OnSceneLoadEvent;
        afterSceneLoaded.OnEventRaised += OnAfterSceneLoadedEvent;
        loadDataEvent.OnEventRaised += OnloadDataEvent;
        backToMenuEvent.OnEventRaised += OnloadDataEvent;
    }

    private void OnDisable() {
        inputControl.Disable();
        sceneLoadEventSO.LoadRequestEvent -= OnSceneLoadEvent;
        afterSceneLoaded.OnEventRaised -= OnAfterSceneLoadedEvent;
        loadDataEvent.OnEventRaised -= OnloadDataEvent;
        backToMenuEvent.OnEventRaised -= OnloadDataEvent;
    }

    private void Update() {
        inputDirection = inputControl.GamePlay.Move.ReadValue<Vector2>();
        CheckStatus();
    }

    private void FixedUpdate() {
        if (!isHurt && !isAttack) {
            Move();
        }
    }

    private void Move() {
        if (isSlide) {  // 如果当前处于滑铲状态则不执行以下逻辑
            return;
        }

        // 移动
        if (!isCrouch && !isWallJump) {
            rb.velocity = new Vector2(inputDirection.x * speed * Time.deltaTime, rb.velocity.y);
        }

        // 翻转
        int faceDir = (int)transform.localScale.x;
        if (inputDirection.x > 0) {
            faceDir = 1;
        }
        if (inputDirection.x < 0) {
            faceDir = -1;
        }
        transform.localScale = new Vector3(faceDir, 1, 1);

        // 人物下蹲
        if (!IsMobilePlatform(Application.platform)) {   // 如果是移动端则去除下蹲操作（遥感操作不方便）
            isCrouch = physicsCheck.isGround && inputDirection.y < 0;
            if (isCrouch) {
                // 修改碰撞体大小和位移
                colli.offset = new Vector2(-0.05f, 0.85f);
                
                colli.size = new Vector2(0.7f, 1.7f);
            } else {
                // 还原之前碰撞体参数
                colli.offset = originalOffset;
                colli.size = originalSize;
            }
        }
    }

    private void Jump(InputAction.CallbackContext CallbackContext) {
        if (physicsCheck.isGround) {
            rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);

            // 打断滑铲协程
            isSlide = false;
            StopAllCoroutines();
        } else if (physicsCheck.isWall) {
            rb.AddForce(new Vector2(-inputDirection.x, 2.5f) * wallJumpForce, ForceMode2D.Impulse);
            Debug.Log("蹬墙跳：");
            Debug.Log(new Vector2(-inputDirection.x, 2.5f) * wallJumpForce);
            isWallJump = true;
        }
    }

    private void Attack(InputAction.CallbackContext CallbackContext) {
        if (isSlide || isCrouch) {
            return;
        }

        playerAnimation.PlayerAttack();
        isAttack = true;
    }

    private void Slide(InputAction.CallbackContext CallbackContext) {
        if (!isSlide && !isCrouch && physicsCheck.isGround && character.curPower >= slidePowerCost) {
            isSlide = true;

            Vector3 targetPos = new Vector3(transform.position.x + slideDistance * transform.localScale.x, transform.position.y);

            // 滑铲的协程
            StartCoroutine(TriggerSlide(targetPos));
            // 滑铲的能量消耗
            character.OnSlide(slidePowerCost);
        }
    }

    /*
        滑铲逻辑的协程
    */
    private IEnumerator TriggerSlide(Vector3 targetPos) {
        do {
            yield return null;

            if (!physicsCheck.isGround) {
                break;
            }

            if ((physicsCheck.touchLeftWall && transform.localScale.x < 0f) || (physicsCheck.touchRightWall && transform.localScale.x > 0f)) {
                break;
            }

            rb.MovePosition(new Vector2(transform.position.x + transform.localScale.x * slideSpeed, transform.position.y));
        } while(MathF.Abs(targetPos.x - transform.position.x) > 0.1f);
        isSlide = false;
    }

    #region UnityEvent
    public void GetHurt(Transform attacker) {
        isHurt = true;
        rb.velocity = Vector2.zero;

        #region 惯性回弹
        // 获得受伤的方向
        // Vector2 dir = new Vector2((transform.position.x - attacker.position.x) > 0 ? 1 : -1, 0);
        Vector2 dir = new Vector2((transform.position.x - attacker.position.x), 0).normalized;  // normalized归一化
        rb.AddForce(dir * hurtForce, ForceMode2D.Impulse);
        #endregion 惯性回弹
    }

    public void PlayerDead() {
        isDead = true;
        inputControl.GamePlay.Disable();
    }
    #endregion UnityEvent

    public void CheckStatus() {  // 游戏中各种状态的检测
        // 检测是否死亡或者处于滑铲状态，如果死亡则把玩家的layer变为Ignore Raycast使敌人不会继续攻击玩家
        if (isDead || isSlide) {
            gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
        } else {
            gameObject.layer = LayerMask.NameToLayer("Player");
        }
        
        // 在地面时使用有摩擦力的物理材质，在空中时为了避免卡在墙面上，使用光滑的物理材质
        colli.sharedMaterial = physicsCheck.isGround ? normal : wall;

        if (physicsCheck.isWall) {
            rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y / 2);
        } else {
            rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y);
        }

        if (isWallJump && rb.velocity.y < 0f) {
            isWallJump = false;
        }
    }

    /// <summary>
    ///     加载场景时执行的事件
    /// </summary>
    private void OnSceneLoadEvent(GameSceneSO scenToLoad, Vector3 posToGo, bool fadeScreen) {
        inputControl.GamePlay.Disable();
    }

    /// <summary>
    ///     数据加载时执行的事件
    /// </summary>
    private void OnloadDataEvent() {
        isDead = false;
    }

    /// <summary>
    ///     场景加载完毕后执行的事件
    /// </summary>
    private void OnAfterSceneLoadedEvent() {
        inputControl.GamePlay.Enable();
    }

    bool IsMobilePlatform(RuntimePlatform platform) {
        return platform == RuntimePlatform.Android || platform == RuntimePlatform.IPhonePlayer;
    }
    
}